﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Reflection;

namespace Open.Core.Runtime
{

    /// <summary>
    /// 依赖引导器
    /// </summary>
    public class DependencyRegistrator
    {
        private ITypeFinder TypeFinder { get; set; }

        private IServiceCollection Services { get; set; }

        private List<Assembly> Assemblies { get; set; }

        private ILogger<DependencyRegistrator> Logger { get; }


        public DependencyRegistrator(IServiceCollection services, ITypeFinder typeFinder)
        {
            TypeFinder = typeFinder ?? new TypeFinder();
            Services = services;
            Assemblies = TypeFinder.GetAssemblies().ToList();
            Logger = Services.BuildServiceProvider().GetRequiredService<ILogger<DependencyRegistrator>>();
        }

        /// <summary>
        /// 获取类型集合
        /// </summary>
        private Type[] GetTypes<T>()
        {
            return TypeFinder.Find<T>(Assemblies).ToArray();
        }
        public IServiceCollection RegisterServices()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            //Logger.LogInformation("开始自动注册服务...");
            RegisterScopeDependency();
            RegisterSingleDependency();
            RegisterTransientDependency();
            watch.Stop();
            //Logger.LogInformation($"结束自动注册服务,耗时\t{watch.ElapsedMilliseconds}\t毫秒");
            return Services;
        }
        private void RegisterSingleDependency()
        {
            var types = TypeFinder.Find<ISingletonDependency>(Assemblies).ToList();
            if (!types.Any())
                return;
            foreach (var type in types)
            {
                var interfaces = type.GetInterfaces();
                foreach (var @interface in interfaces.Where(x => x != typeof(ISingletonDependency)))
                {
                    //Logger.LogInformation($"{type.Name}\t---->\t{@interface.Name}");
                    Services.TryAddSingleton(@interface, type);
                }
            }
        }

        private void RegisterTransientDependency()
        {
            var types = TypeFinder.Find<ITransientDependency>(Assemblies).ToList();
            if (!types.Any())
                return;
            foreach (var type in types)
            {
                var interfaces = type.GetInterfaces();
                foreach (var @interface in interfaces.Where(x => x != typeof(IScopeDependency)))
                {
                    Services.TryAddTransient(@interface, type);
                }
            }
        }

        private void RegisterScopeDependency()
        {
            var types = TypeFinder.Find<IScopeDependency>(Assemblies).ToList();
            if (!types.Any())
                return;
            foreach (var type in types)
            {
                var interfaces = type.GetInterfaces();
                foreach (var @interface in interfaces.Where(x => x != typeof(IScopeDependency)))
                {
                    //Logger.LogInformation($"{type.Name}\t---->\t{@interface.Name}");
                    Services.TryAddScoped(@interface, type);
                }
            }
        }
    }
}
